﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using HalconDotNet;
using Microsoft.Win32;

namespace ImageControl
{
    public class WindowCtrl : INotifyPropertyChanged, IDisposable
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private HImageShow imageWindow = null;

        /// <summary>
        /// 待显示object
        /// </summary>
        private ObservableCollection<HWndImage> hImageList = new ObservableCollection<HWndImage>();
        public ObservableCollection<HWndImage> ImageList
        {
            get { return hImageList; }
        }
        /// <summary>
        /// 待显示object
        /// </summary>
        private List<HWndObject> hObjectList = new List<HWndObject>();

        /// <summary>
        /// 待显示文本
        /// </summary>
        private List<HWndMessage> hMsgList = new List<HWndMessage>();

        private HObject hImage;
        public HObject HImage
        {
            get => hImage;
            private set
            {
                hImage = value;
                if (HImage != null && HImage.IsInitialized())
                {
                    imageWidth.Dispose();
                    imageHeight.Dispose();
                    HOperatorSet.GetImageSize(HImage, out imageWidth, out imageHeight);
                }

            }
        }

        private string _ShowImageName = "";
        public string ShowImageName
        {
            get { return _ShowImageName; }
            set
            {
                _ShowImageName = value;
                OnPropertyChanged();
                if (!string.IsNullOrEmpty(_ShowImageName))
                {
                    FitImageWindow();
                }
            }
        }

        private bool _ShowImageSelect = true;
        public bool ShowImageSelect
        {
            get { return _ShowImageSelect; }
            set
            {
                _ShowImageSelect = value;
                OnPropertyChanged();
            }
        }

        private bool _ShowImageMessage = true;
        public bool ShowImageMessage
        {
            get { return _ShowImageMessage; }
            set
            {
                _ShowImageMessage = value;
                OnPropertyChanged();
            }
        }

        private bool _CanMove = true;
        public bool CanMove
        {
            get { return _CanMove; }
            set
            {
                _CanMove = value;
                OnPropertyChanged();
                this.imageWindow.imageWnd.HMoveContent = _CanMove;
            }
        }

        private bool _CanScale = true;
        public bool CanScale
        {
            get { return _CanScale; }
            set
            {
                _CanScale = value;
                OnPropertyChanged();
                //if (_CanScale)
                //{
                //    this.imageWindow.imageWnd.HZoomContent = HSmartWindowControlWPF.ZoomContent.WheelForwardZoomsIn;
                //}
                //else
                //{
                //    this.imageWindow.imageWnd.HZoomContent = HSmartWindowControlWPF.ZoomContent.Off;
                //}

            }
        }


        private string _ImageMessage = "";
        public string ImageMessage
        {
            get { return _ImageMessage; }
            set
            {
                _ImageMessage = value;
                OnPropertyChanged();
            }
        }

        private ContextMenu menu = null;
        private MenuItem saveImageMenu = null;
        private MenuItem saveWindowMenu = null;
        private MenuItem fitWindowMenu = null;

        private HTuple imageWidth = new HTuple();
        private HTuple imageHeight = new HTuple();
        private double zoomWndFactor = 1.0f;

        public WindowCtrl(HImageShow imageWindow)
        {
            this.imageWindow = imageWindow;
            this.imageWindow.imageWnd.HDoubleClickToFitContent = false;
            this.imageWindow.imageWnd.HZoomContent = HSmartWindowControlWPF.ZoomContent.Off;
            this.imageWindow.imageWnd.HMouseMove += ImageWnd_HMouseMove;
            this.imageWindow.imageWnd.HMouseWheel += ImageWnd_HMouseWheel;
            menu = new ContextMenu();
            fitWindowMenu = new MenuItem() { ToolTip = "图像适应窗口显示", Header = "适应窗口" };
            fitWindowMenu.Click += FitWindowMenu_Click;
            saveImageMenu = new MenuItem() { ToolTip = "保存原始图像", Header = "保存原图" };
            saveImageMenu.Click += SaveImageMenu_Click;
            saveWindowMenu = new MenuItem() { ToolTip = "保存窗口截屏", Header = "窗口截屏" };
            saveWindowMenu.Click += SaveWindowMenu_Click;
            menu.Items.Add(fitWindowMenu);
            menu.Items.Add(saveImageMenu);
            menu.Items.Add(saveWindowMenu);
            this.imageWindow.imageWnd.ContextMenu = menu;
        }

        private void FitWindowMenu_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            FitImageWindow();
        }

        private void ImageWnd_HMouseMove(object sender, HSmartWindowControlWPF.HMouseEventArgsWPF e)
        {
            GetImageGrayval(e.Row, e.Column);
        }


        private void ImageWnd_HMouseWheel(object sender, HSmartWindowControlWPF.HMouseEventArgsWPF e)
        {
            if (!CanScale)
            {
                return;
            }
            int mode = 1;
            if (e.Delta > 0)
            {
                mode = 1;
            }
            else
            {
                mode = -1;
            }
            DispWindowZoom(mode, e.Row, e.Column);

        }

        private void DispWindowZoom(int mode, double Mouse_row, double Mouse_col)
        {
            int current_beginRow, current_beginCol, current_endRow, current_endCol;
            int zoom_beginRow, zoom_beginCol, zoom_endRow, zoom_endCol;
            try
            {
                this.imageWindow.imageWnd.HalconWindow.GetPart(out current_beginRow, out current_beginCol, out current_endRow, out current_endCol);
            }
            catch
            {
                return;
            }

            if (mode > 0)                 // 放大图像:窗口大小不变，显示指定的部分图像：显示的图像只是图像的一部分。所以坐标值都是正值。
            {
                zoom_beginRow = (int)(current_beginRow + (Mouse_row - current_beginRow) * 0.300d); //起始点要增加
                zoom_beginCol = (int)(current_beginCol + (Mouse_col - current_beginCol) * 0.300d);
                zoom_endRow = (int)(current_endRow - (current_endRow - Mouse_row) * 0.300d);       //结束点要减小
                zoom_endCol = (int)(current_endCol - (current_endCol - Mouse_col) * 0.300d);
            }
            else                // 缩小图像：窗口大小不变，显示全部图像及图像外围部分。所以坐标值起始部分是负值，结束部分要大于图像的最大坐标。
            {
                zoom_beginRow = (int)(Mouse_row - (Mouse_row - current_beginRow) / 0.700d);  //起始点要减小
                zoom_beginCol = (int)(Mouse_col - (Mouse_col - current_beginCol) / 0.700d);
                zoom_endRow = (int)(Mouse_row + (current_endRow - Mouse_row) / 0.700d);      //结束点要增加。
                zoom_endCol = (int)(Mouse_col + (current_endCol - Mouse_col) / 0.700d);
            }

            try
            {
                double hw_width, hw_height;
                hw_width = this.imageWindow.imageWnd.ActualWidth;
                hw_height = this.imageWindow.imageWnd.ActualHeight;

                bool _isOutOfArea = true;
                bool _isOutOfSize = true;
                bool _isOutOfPixel = true;  //避免像素过大

                _isOutOfArea = zoom_beginRow >= imageHeight.I || zoom_endRow <= 0 || zoom_beginCol >= imageWidth.I || zoom_endCol < 0;
                _isOutOfSize = (zoom_endRow - zoom_beginRow) > imageHeight.I * 20 || (zoom_endCol - zoom_beginCol) > imageWidth.I * 20;
                _isOutOfPixel = hw_height / (zoom_endRow - zoom_beginRow) > 500 || hw_width / (zoom_endCol - zoom_beginCol) > 500;

                if (_isOutOfArea || _isOutOfSize || _isOutOfPixel)
                {
                    return;
                }

                //保持图像显示比例:根据窗口的长宽比例，显示也要做相应调整。
                if (hw_width / hw_height > 1) //因为宽>高。所以要锁定高值（zoom_endRow-zoom_beginRow），再等比例增加宽值=高值* hw_width / hw_height
                {
                    this.imageWindow.imageWnd.HalconWindow.SetPart(zoom_beginRow, zoom_beginCol, zoom_endRow, zoom_beginCol + (zoom_endRow - zoom_beginRow) * hw_width / hw_height);
                }

                else                  //因为高>宽。所以要锁定宽值（zoom_endCol-zoom_beginCol），再等比例增加高值=宽值* hw_height / hw_width
                {
                    this.imageWindow.imageWnd.HalconWindow.SetPart(zoom_beginRow, zoom_beginCol, zoom_beginRow + (zoom_endCol - zoom_beginCol) * hw_height / hw_width, zoom_endCol);
                }
                int w = (int)((zoom_endRow - zoom_beginRow) * hw_width / hw_height);
                int w0 = current_endCol - current_beginCol;
                double scale = (double)w / w0;
                zoomWndFactor *= scale;
                Repaint();
            }
            catch
            {

            }
        }

        private void SaveWindowMenu_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            if (this.imageWindow.HalconWnd == null || !this.imageWindow.HalconWnd.IsInitialized())
            {
                return;
            }
            if (HImage == null || !HImage.IsInitialized())
            {
                return;
            }
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "PNG图像|*.png|所有文件|*.*";

            if (sfd.ShowDialog() == true)
            {
                if (String.IsNullOrEmpty(sfd.FileName))
                    return;

                //截取窗口图
                HOperatorSet.DumpWindow(this.imageWindow.HalconWnd, "png best", sfd.FileName);
            }
        }


        private void SaveImageMenu_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            if (HImage == null || !HImage.IsInitialized())
            {
                return;
            }
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.Filter = "PNG图像|*.png|所有文件|*.*";
            if (sfd.ShowDialog() == true)
            {
                if (String.IsNullOrEmpty(sfd.FileName))
                {
                    return;
                }
                HOperatorSet.WriteImage(HImage, "png best", 0, sfd.FileName);
            }
        }





        public void GetImageGrayval(double row, double column)
        {
            if (this.imageWindow.HalconWnd == null || !this.imageWindow.HalconWnd.IsInitialized())
            {
                return;
            }
            if (HImage == null || !HImage.IsInitialized())
            {
                return;
            }
            try
            {
                double positionX, positionY;
                bool _isXOut = true, _isYOut = true;
                HTuple channel_count = new HTuple();
                HOperatorSet.CountChannels(HImage, out channel_count);
                positionY = row;
                positionX = column;
                _isXOut = (positionX < 0 || positionX >= imageWidth.I);
                _isYOut = (positionY < 0 || positionY >= imageHeight.I);
                ImageMessage = $"W:{imageWidth},H:{imageHeight} | X:{positionX.ToString("f2")},Y:{positionY.ToString("f2")}";
                if (!_isXOut && !_isYOut)
                {
                    if ((int)channel_count == 1)
                    {
                        HOperatorSet.GetGrayval(HImage, positionY, positionX, out HTuple grayVal);
                        ImageMessage += $" | Gray:{grayVal.D:000}";
                    }
                    else if ((int)channel_count == 3)
                    {
                        HObject redChannel = null, greenChannel = null, blueChannel = null;
                        HOperatorSet.GenEmptyObj(out redChannel);
                        HOperatorSet.GenEmptyObj(out greenChannel);
                        HOperatorSet.GenEmptyObj(out blueChannel);
                        redChannel.Dispose();
                        greenChannel.Dispose();
                        blueChannel.Dispose();

                        HOperatorSet.AccessChannel(HImage, out redChannel, 1);
                        HOperatorSet.AccessChannel(HImage, out greenChannel, 2);
                        HOperatorSet.AccessChannel(HImage, out blueChannel, 3);

                        HOperatorSet.GetGrayval(redChannel, positionY, positionX, out HTuple grayValRed);
                        HOperatorSet.GetGrayval(greenChannel, positionY, positionX, out HTuple grayValGreen);
                        HOperatorSet.GetGrayval(blueChannel, positionY, positionX, out HTuple grayValBlue);

                        redChannel.Dispose();
                        greenChannel.Dispose();
                        blueChannel.Dispose();
                        ImageMessage += $" | R:{grayValRed.D:000},G:{grayValGreen.D:000},B:{grayValBlue.D:000}";
                    }
                }
            }
            catch
            {
                return;
            }
        }

        public void FitImageWindow()
        {
            if (this.imageWindow.HalconWnd == null || !this.imageWindow.HalconWnd.IsInitialized())
            {
                return;
            }
            if (hImageList.Count == 0)
            {
                return;
            }
            if (string.IsNullOrEmpty(ShowImageName))
            {
                HImage = hImageList[0].HImage;
                ShowImageName = hImageList[0].Name;
            }
            else
            {
                HImage = hImageList.FirstOrDefault(x => x.Name == ShowImageName).HImage;
            }
            if (HImage == null || !HImage.IsInitialized())
            {
                return;
            }
            HSystem.SetSystem("flush_graphic", "false");
            double ScaleC = (double)imageWidth / this.imageWindow.ActualWidth;
            double ScaleR = (double)imageHeight / this.imageWindow.ActualHeight;
            double w, h;
            double imgRow1, imgCol1, imgRow2, imgCol2;
            if (ScaleC < ScaleR)
            {
                zoomWndFactor = ScaleR;
                h = this.imageWindow.ActualHeight * ScaleR;
                w = this.imageWindow.ActualWidth * ScaleR;
                imgRow1 = 0;
                imgCol1 = (imageWidth - w) / 2.0;  //为了窗口横向正好显示在中间，左右两边各余留距离：(imageWidth - w) / 2.0
            }
            else
            {
                zoomWndFactor = ScaleC;
                h = this.imageWindow.ActualHeight * ScaleC;
                w = this.imageWindow.ActualWidth * ScaleC;

                imgRow1 = (imageHeight - h) / 2.0; //为了窗口纵向正好显示在中间，上下两边各余留距离：(imageWidth - w) / 2.0
                imgCol1 = 0;
            }
            imgRow2 = imgRow1 + h - 1;
            imgCol2 = imgCol1 + w - 1;
            this.imageWindow.HalconWnd.SetPart(imgRow1, imgCol1, imgRow2, imgCol2);
            this.imageWindow.HalconWnd.ClearWindow();
            this.imageWindow.HalconWnd.DispObj(HImage);
            //显示Objects
            ShowHObjectList(this.imageWindow.HalconWnd);
            HSystem.SetSystem("flush_graphic", "true");
        }


        public void Repaint()
        {
            if (this.imageWindow.HalconWnd == null || !this.imageWindow.HalconWnd.IsInitialized())
            {
                return;
            }
            if (HImage == null || !HImage.IsInitialized())
            {
                return;
            }
            HSystem.SetSystem("flush_graphic", "false");
            this.imageWindow.HalconWnd.ClearWindow();
            this.imageWindow.HalconWnd.DispObj(HImage);
            //显示Objects
            ShowHObjectList(this.imageWindow.HalconWnd);
            HSystem.SetSystem("flush_graphic", "true");
        }
        public void AddImage(HWndImage wndImage)
        {
            hImageList.Add(wndImage);
        }

        public void AddObject(HWndObject hObjectWithColor)
        {
            hObjectList.Add(hObjectWithColor);
        }

        public void AddText(HWndMessage msg)
        {
            hMsgList.Add(msg);
        }

        /// <summary>
        /// 清除所有hobject
        /// </summary>
        public void ClearAllList()
        {
            foreach (HWndImage himage in hImageList)
            {
                himage.HImage?.Dispose();
            }
            foreach (HWndObject hObjectWithColor in hObjectList)
            {
                hObjectWithColor.HObj?.Dispose();
            }
            hImageList.Clear();
            hObjectList.Clear();
            hMsgList.Clear();
        }

        /// <summary>
        /// 清除所有hobject
        /// </summary>
        public void ClearHObjects()
        {
            foreach (HWndObject hObjectWithColor in hObjectList)
            {
                hObjectWithColor.HObj?.Dispose();
            }
            hObjectList.Clear();
        }

        /// <summary>
        /// 显示hobject
        /// </summary>
        private void ShowHObjectList(HWindow window)
        {
            if (window == null || !window.IsInitialized())
            {
                return;
            }
            foreach (HWndObject hObjectWithColor in hObjectList)
            {
                window.SetColor(hObjectWithColor.Color);
                window.DispObj(hObjectWithColor.HObj);
            }
            foreach (HWndMessage msg in hMsgList)
            {
                msg.SetFont(window, (1.0) / zoomWndFactor);
                msg.DispText(window);
            }
        }

        public bool IsDisposed { get; set; } = false;
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        void Dispose(bool disposing)
        {
            if (disposing)
            {
                ClearAllList();
                IsDisposed = true;
            }
        }
        ~WindowCtrl()
        {
            Dispose(false);
        }

    }
}
